import { 
  AmbientLight,
  BufferGeometry,
  AxesHelper,
  Color, 
  CubicBezierCurve, 
  CubicBezierCurve3,
  SpotLight, 
  PlaneGeometry,
  MeshLambertMaterial,
  LineBasicMaterial, 
  Mesh, 
  MeshBasicMaterial, 
  OrthographicCamera, 
  PerspectiveCamera, 
  PlaneBufferGeometry, 
  Scene, 
  ShaderMaterial, 
  Vector3, 
  WebGLRenderer, 
  Line, 
  BoxGeometry, 
  CatmullRomCurve3,
  TubeBufferGeometry
} from "three";
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls';
import stats from '../utils/stats';
import { GUI } from 'dat.gui';

const scene = new Scene();
const renderer = new WebGLRenderer({ antialias: true });
renderer.setClearColor(new Color(0x000000));
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;

const camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(-50, 30, 20);
camera.lookAt(new Vector3(-10, 0, 0));

// 创建平面 
const planeGeometry = new PlaneGeometry(60, 40, 1, 1);
const planeMaterial = new MeshLambertMaterial({ color: 0x333333 });
const plane = new Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
plane.rotation.x = -0.5 * Math.PI;
plane.position.set(0, 0, 0);
scene.add(plane);

// 片元着色器
const fragmentShader = `
#include <common>

uniform vec2 u_resolution;
uniform float u_time;
// 接收颜色
uniform vec3 u_color;
// 背景色
uniform vec3 u_bgColor;

float box(in vec2 _st, in vec2 _size){
  _size = vec2(0.5) - _size*0.5;
  vec2 uv = smoothstep(_size, _size+vec2(0.001), _st);
  uv *= smoothstep(_size, _size+vec2(0.001), vec2(1.0)-_st);
  return uv.x*uv.y;
}

float cross(in vec2 _st, float _size){
  return  box(_st, vec2(_size/4.0, _size));
}

varying vec2 vUv;

void main(){
  vec2 fragCoord = vUv * u_resolution.xy;

  vec2 st = fragCoord.xy / u_resolution.xy;
  vec3 color = u_bgColor;

  // st -= vec2(0.5);

  // To move the cross we move the space
  // vec2 translate = vec2(0, (u_time - 50.) / 50.);
  vec2 translate = vec2(-(u_time - 50.) / 50., 0.);
  // vec2 translate = vec2(-0.5, 0.);
  st += translate;

  // Add the shape on the foreground
  color += vec3(cross(st, 1.0)) * u_color;

  gl_FragColor = vec4(color, 1.0);
}
`;

const vertexShader = `
#include <common>

uniform float step;
varying vec2 vUv;

void main() {
  vUv = uv;

  gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`;

const uniforms = {
  u_time: { value: 0.0 },
  u_resolution: { value: new Vector3() },
  u_color: { value: new Color(0xff0000) },
  u_bgColor: { value: new Color(0x000000) }
}
const material = new ShaderMaterial({
  transparent: true,
  fragmentShader,
  vertexShader,
  uniforms
})
// scene.add(new Mesh(plane, material))

scene.add(new AmbientLight(0xffffff))
// 添加坐标系，方便理解
const axes = new AxesHelper(20)
scene.add(axes)

const curve = new CubicBezierCurve3(
  new Vector3(-10, 0, 0),
  new Vector3(-10, 10, 0),
  new Vector3(10, 10, 0),
  new Vector3(10, 0, 0),
)
const points = curve.getPoints(50)
console.log(points)

const geom = new BufferGeometry().setFromPoints(points)
const flyLine = new Line(geom, material)
flyLine.position.set(0, 0, 0)
scene.add(flyLine)

const boxGeo = new BoxGeometry(4, 5, 2, 2)
const box = new Mesh(boxGeo, material)
box.position.set(0, 6, 4)
scene.add(box);

for (let i = 0; i < 1000; i++) {
  const line = new CatmullRomCurve3([
    new Vector3(0, 0, 0),
    new Vector3(-Math.random() * 10, 0, Math.random() * 10),
    new Vector3(-Math.random() * 20, 0, Math.random() * 20)
  ]);
  const tubeGeom = new TubeBufferGeometry(line, 20, 0.02, 20, false);
  const tubeMesh = new Mesh(tubeGeom, material);
  scene.add(tubeMesh);
}

// 添加光源
const ambientLight = new AmbientLight(0x555555)
scene.add(ambientLight)

document.body.appendChild(renderer.domElement);

const gui = new GUI();
const controls = {
  color: 0xffffff,
  bgColor: 0x464444,
};

uniforms.u_color.value = new Color(controls.color);
uniforms.u_bgColor.value = new Color(controls.bgColor);

gui.addColor(controls, 'color').onChange(val => {
  uniforms.u_color.value = new Color(val);
});
gui.addColor(controls, 'bgColor').onChange(val => {
  uniforms.u_bgColor.value = new Color(val);
});

const trackballControls = new TrackballControls(camera, renderer.domElement)

function render(time: number) {
  time *= 0.001;

  trackballControls.update();
  stats.update();

  const canvas = renderer.domElement
  uniforms.u_resolution.value.set(canvas.width, canvas.height, 1)
  // uniforms.u_time.value = 0
  if (uniforms.u_time.value >= 100) {
    uniforms.u_time.value = 0
  } else {
    uniforms.u_time.value += 1
  }

  requestAnimationFrame(render)
  renderer.render(scene, camera)
}

requestAnimationFrame(render)